
#ifndef GRID
#define GRID

#include "position.h"
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

#define NORTH 1
#define SOUTH 2
#define EAST 3
#define WEST 4
#define GRID_SIZE 40

using namespace std;

class Grid {
	
	public:
	
	Position position;
	Grid * north;
	Grid * south;
	Grid * east;
	Grid * west;
	
	bool has_robot;
	bool isstart;
	
	Grid();
	Grid( int px, int py );
	~Grid();
	
	Grid& add_grid( int direction );
	void add_grid( int direction, Grid * g );
	bool is_free( int direction ) const;
	Grid* get_grid( int direction ) const;
	int get_x() const { return position.x; }
	int get_y() const { return position.y; }
	const Position& get_position() const { return position; }
	
	void enter() { has_robot = true; }
	void leave() { has_robot = false; }
	void set_start() { isstart = true; }
	const bool is_start() { return isstart; }
	
	friend ostream & operator<<( ostream &out, const Grid & g ) {
		out << "( " << g.get_x() << ", " << g.get_y() << " )";
		return out;
	}
	
	const bool operator==( Grid const & ) const;
	const bool operator<( Grid const & ) const;
	
};

Grid::Grid() : position(0,0), has_robot(0), isstart(0) {}
 
Grid::Grid( int px, int py ) : position(px,py), has_robot(0), isstart(0) {
	north = 0;
	south = 0;
	east = 0;
	west = 0;
}

Grid::~Grid() {}

const bool Grid::operator==( Grid const & g ) const {
	return ( get_x() == g.get_x() && get_y() == g.get_y() );
} 

const bool Grid::operator<( Grid const & g ) const {
	return get_position() < g.get_position();
}

Grid* Grid::get_grid(int direction) const {
	switch( direction ) {
		case NORTH: return north;
		case SOUTH: return south;
		case EAST: return east;
		case WEST: return west;
		default: return north;
	}	
}

bool Grid::is_free(int direction) const {
	switch( direction ) {
		case NORTH: return north != 0;
		case SOUTH: return south != 0;
		case EAST: return east != 0;
		case WEST: return west != 0;
		default: return false;
	}
}

void Grid::add_grid( int direction, Grid * g ) {
	switch( direction ) {
		case NORTH:{
			north = g;
			(*g).south = this;
		}
		break;
		case SOUTH: {
			south = g;
			(*g).north = this;
		}
		break;
		case EAST: {
			east = g;
			(*g).west = this;
		}
		break;
		case WEST: {
			west = g;
			(*g).east = this;
		}
		break;
		default: break;
	}	
}

Grid& Grid::add_grid( int direction ) {
	
	Grid *g = 0;
	
	switch( direction ) {
		case NORTH:{
			g = new Grid( get_x(), get_y()+GRID_SIZE );
			north = g;
			(*g).south = this;
		}
		break;
		case SOUTH: {
			g = new Grid( get_x(), get_y()-GRID_SIZE );
			south = g;
			(*g).north = this;
		}
		break;
		case EAST: {
			g = new Grid( get_x()+GRID_SIZE, get_y() );
			east = g;
			(*g).west = this;
		}
		break;
		case WEST: {
			g = new Grid( get_x()-GRID_SIZE, get_y() );
			west = g;
			(*g).east = this;
		}
		break;
		default: break;
	}
	
	return *g;
	
}

#endif

